/*
 * @Author: Cao Shixin
 * @Date: 2021-01-29 15:15:34
 * @LastEditors: Cao Shixin
 * @LastEditTime: 2021-07-08 10:15:45
 * @Description: 
 */
import 'dart:async';
import 'dart:io';

import 'package:flutter/foundation.dart';
import 'package:logger_csx/logger_csx.dart';

import 'log_const.dart';
import 'log_model.dart';
import 'log_path.dart';
import 'log_setup.dart';
import 'log_util.dart';

final _buffer = StringBuffer();

const String _separator = ',';

/*初始化logger
 * 
 * filter：过滤器
 * isConsole：是否是控制台打印输出（false表示存储本地文件）
 * // 以下参数isConsole为false的时候才有意义
 * fileHeadNotifier: 文件存储的头部信息，可以随时设置变更，变更的头文件信息会在创建新文件的时候才生效，之前创建的log文件头部信息不会变更
 * fileHead：文件存储的头部信息，用来记录设备和app的一些共有信息，默认没有，已废弃，使用[fileHeadNotifier]替换
 * maxFileCount 设置文件最大数量（目前以天为单位），默认7个
 */
Future initLogger({
  LogFilter? filter,
  bool isConsole = kDebugMode,
  ValueNotifier<String>? fileHeadNotifier,
  @Deprecated(
      '之前的头部信息，隐私政策调整，取消使用，用[fileHeadNotifier]替换，两个都设置以fileHeadNotifier为主')
  String fileHead = '',
  num maxFileCount = 7,
  void Function(LogEvent event)? onLogEvent,
  String? loggerDir,
}) async {
  if (loggerDir != null) {
    LogPath.loggerDir = loggerDir;
  }
  LogPath.checkLoggerFile(maxFileCount: maxFileCount);
  var fileFront = fileHead;
  if (fileHeadNotifier != null) {
    fileFront = fileHeadNotifier.value;
  }
  fileHeadNotifier?.addListener(() {
    fileFront = fileHeadNotifier.value;
  });
  var logPath = await LogPath.getLoggerDir();
  if (!await Directory(logPath).exists()) {
    await Directory(logPath).create(recursive: true);
  }
  var loggerPrinter;
  var loggerOutPut;
  if (isConsole) {
    loggerPrinter = LogDatePrinter();
    loggerOutPut = ConsoleLogOutput();
  } else {
    loggerPrinter = SimplePrinter();
    loggerOutPut = StreamOutput()
      ..stream
          .asyncMap((event) async => await _onlyWriteFileNoThreshold(
              event, logPath,
              fileHeader: fileFront))
          .listen((event) {});
  }
  _logger = Logger(
    filter: filter ?? ProductionFilter(),
    printer: onLogEvent == null
        ? loggerPrinter
        : LogPrinterWrapper(printer: loggerPrinter, onLogEvent: onLogEvent),
    output: loggerOutPut,
  );
}

class LogPrinterWrapper extends LogPrinter {
  final LogPrinter printer;
  final void Function(LogEvent event)? onLogEvent;

  LogPrinterWrapper({required this.printer, this.onLogEvent});

  @override
  void init() {
    printer.init();
  }

  @override
  List<String> log(LogEvent event) {
    onLogEvent?.call(event);
    return printer.log(event);
  }

  @override
  void destroy() {
    printer.destroy();
  }
}

//仅作写入文件
Future _onlyWriteFileNoThreshold(OutputEvent event, String logPath,
    {String fileHeader = ''}) async {
  var timeNowSimpleStr = logSimpleFormat.format(DateTime.now());
  var logLever = LogDatePrinter.levelPrefixes[event.level];
  var logExtraParam = LogExtraParam.fromJson(event.extraParam);
  await _cellSaveFile(event, timeNowSimpleStr, logPath, logLever, logExtraParam,
      fileHeader: fileHeader);
}

/*
 * 保存文件
 */
Future _cellSaveFile(OutputEvent event, String timeNowSimpleStr, String baseDir,
    String? logLever, LogExtraParam logExtraParam,
    {String fileHeader = ''}) async {
  //文件
  var filePath = baseDir + '/' + timeNowSimpleStr;
  var fileFloder = Directory(filePath);
  if (!await fileFloder.exists()) {
    await fileFloder.create(recursive: true);
  }
  //文件存储操作
  var loggerFile = File(filePath + '/' + logExtraParam.fileSubName);
  _buffer.clear();
  if (!await loggerFile.exists()) {
    //创建新文件时，首先写入App信息，设备信息
    await loggerFile.create(recursive: true);
    fileHeader.split('/n').forEach((str) {
      _buffer.writeln(str);
    });
    _buffer.writeln();
  }
  _buffer.write(logDateFormat.format(DateTime.now()));
  _buffer.write(_separator);
  _buffer.write(logLever);
  _buffer.write(_separator);
  _buffer.write('[${logExtraParam.tag}]');
  _buffer.write(_separator);
  _buffer.writeAll(event.lines);
  _buffer.writeln();
  try {
    loggerFile.writeAsStringSync(_buffer.toString(),
        mode: FileMode.writeOnlyAppend);
  } catch (e) {
    LogUtil.logE('FileOutPut, $e');
  }
}

/*
 *  lazy计划
 */
Logger? _logger;

Logger get logger {
  if (_logger == null) {
    _logger = Logger(printer: LogDatePrinter());
  }
  return _logger!;
}

class StreamOutput extends LogOutput {
  late StreamController<OutputEvent> _controller;

  // ignore: unused_field
  bool _shouldForward = false;

  StreamOutput() {
    _controller = StreamController<OutputEvent>(
      onListen: () => _shouldForward = true,
      onPause: () => _shouldForward = false,
      onResume: () => _shouldForward = true,
      onCancel: () => _shouldForward = false,
    );
  }

  Stream<OutputEvent> get stream => _controller.stream;

  @override
  void output(OutputEvent event) {
    // if (!_shouldForward) {
    //   return;
    // }
    _controller.add(event);
  }

  @override
  void destroy() {
    _controller.close();
  }
}
